package com.netposa.datawarehouse.statistics.service;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.netposa.datawarehouse.aggregator.client.search.BodyResourceSearch;
import com.netposa.datawarehouse.aggregator.client.search.FaceResourceSearch;
import com.netposa.datawarehouse.aggregator.client.search.NonmotorResourceSearch;
import com.netposa.datawarehouse.aggregator.client.search.VehicleResourceSearch;
import com.netposa.datawarehouse.aggregator.web.model.DefaultCondition;
import com.netposa.datawarehouse.aggregator.web.model.FtrCondition;
import com.netposa.datawarehouse.aggregator.web.model.SearchDataType;
import com.netposa.datawarehouse.statistics.StatisticsClient;
import com.netposa.datawarehouse.statistics.common.RecordType;
import com.netposa.datawarehouse.statistics.vo.DeviceCountVO;
import com.netposa.datawarehouse.statistics.vo.StructureCountExVO;
import com.netposa.datawarehouse.statistics.vo.StructureCountVO;
import com.netposa.datawarehouse.statistics.vo.TimeAxisCountVO;
import com.netposa.datawarehouse.statistics.vo.TimeCountVO;
import com.netposa.npwonder.base.model.ResponseData;
import com.netposa.npwonder.base.util.BusinessServerId;
import com.netposa.npwonder.base.util.RestAssert;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jodd.datetime.JDateTime;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Service
public class StructureService {
   private static final Logger log = LoggerFactory.getLogger(com.netposa.datawarehouse.statistics.service.StructureService.class);

   @Autowired
   private StatisticsClient statisticsClient;

   @Autowired
   private VehicleResourceSearch vehicleResourceSearch;

   @Autowired
   private FaceResourceSearch faceResourceSearch;

   @Autowired
   private BodyResourceSearch bodyResourceSearch;

   @Autowired
   private NonmotorResourceSearch nonmotorResourceSearch;

   @Autowired
   private RestAssert restAssert;

   public StructureCountVO typeCount(String types) {
      Map<RecordType, Long> recordMap = this.statisticsClient.typeCount();
      if (StringUtils.isEmpty(types))
         return new StructureCountVO(recordMap.get(RecordType.face), recordMap.get(RecordType.body), recordMap.get(RecordType.vehicle), recordMap.get(RecordType.nonmotor), recordMap.get(RecordType.wifi), recordMap.get(RecordType.rfid));
      List<String> typeList = Splitter.on(",").splitToList(types);
      StructureCountVO structureCountVO = new StructureCountVO();
      typeList.stream().forEach(str -> {
         try {
            String temp = str;
            if ("body".equals(str))
               temp = "human";
            Field field = structureCountVO.getClass().getDeclaredField(temp);
            field.setAccessible(true);
            field.set(structureCountVO, recordMap.get(RecordType.valueOf(str)));
         } catch (NoSuchFieldException e) {
            log.error("typeCount NoSuchFieldException ->{},this field str is ->{}", e, str);
         } catch (IllegalAccessException e) {
            log.error("typeCount IllegalAccessException ->{},this field str is ->{}", e, str);
         }
      });
      return new StructureCountVO(structureCountVO.getFace(), structureCountVO.getHuman(), structureCountVO.getVehicle(), structureCountVO
              .getNonmotor(), structureCountVO.getWifi(), structureCountVO.getRfid());
   }

   public List<TimeCountVO> timelineCount(String types) {
      List<TimeCountVO> retVal = Lists.newArrayList();
      List<String> typeList = new ArrayList<>();
      if (StringUtils.isNotBlank(types))
         typeList = Arrays.asList(types.split(","));
      Date now = new Date();
      for (int i = 0; i > -7; i--) {
         long time = DateUtils.addDays(now, i).getTime();
         retVal.add(new TimeCountVO(this.statisticsClient.todayStructureByTypes(typeList, Long.valueOf(time)), (new DateTime(time)).toString("MM-dd")));
      }
      return retVal;
   }

   public List<TimeAxisCountVO> timelineCountByDays(String types, int day) {
      List<TimeAxisCountVO> timeAxisCountVOS = new ArrayList<>();
      List<String> faceList = new ArrayList<>();
      List<String> vehicleList = new ArrayList<>();
      if (StringUtils.isNotBlank(types))
         for (String type : types.split(",")) {
            if (type.equals("face"))
               faceList.add(type);
            if (type.equals("vehicle"))
               vehicleList.add(type);
         }
      Date now = new Date();
      for (int i = 0; i > -day; i--) {
         long time = DateUtils.addDays(now, i).getTime();
         TimeAxisCountVO timeAxisCountVO = new TimeAxisCountVO();
         timeAxisCountVO.setCount(this.statisticsClient.todayStructure(Long.valueOf(time)).longValue());
         timeAxisCountVO.setFaceCount(this.statisticsClient.todayStructureByTypes(faceList, Long.valueOf(time)).longValue());
         timeAxisCountVO.setVehicleCount(this.statisticsClient.todayStructureByTypes(vehicleList, Long.valueOf(time)).longValue());
         timeAxisCountVO.setTime((new DateTime(time)).toString("MM-dd"));
         timeAxisCountVOS.add(timeAxisCountVO);
      }
      return timeAxisCountVOS;
   }

   public Object taskCount() {
      return null;
   }

   public JSONObject cameracount(String regionName) {
      JSONObject retVal = new JSONObject();
      for (String name : regionName.split(",")) {
         ResponseData responseData = this.restAssert.getBusinessAssert(BusinessServerId.search).postData(name, "/map_region/queryRegionCount");
         if (responseData.code == 200)
            retVal.put(name, responseData.getData().toJavaObject(DeviceCountVO.class));
      }
      return retVal;
   }

   public JSONObject regioncount(String regionName) {
      JSONObject retVal = new JSONObject();
      ResponseData responseData = this.restAssert.getBusinessAssert(BusinessServerId.search).postData(regionName, "/map_region/queryRegionCamera");
      if (responseData.code == 200) {
         JSONObject data = responseData.getData();
         Map<String, Map<RecordType, Long>> deviceMap = this.statisticsClient.deviceTypeCount();
         for (String name : regionName.split(",")) {
            List<String> cameras = data.getJSONArray(name).toJavaList(String.class);
            long face = 0L, human = 0L, vehicle = 0L, nonmotor = 0L;
            if (!CollectionUtils.isEmpty(cameras))
               for (String cameraId : cameras) {
                  for (String key : deviceMap.keySet()) {
                     if (key.equals(cameraId)) {
                        Map<RecordType, Long> recordMap = deviceMap.get(key);
                        face += ((Long)recordMap.get(RecordType.face)).longValue();
                        human += ((Long)recordMap.get(RecordType.body)).longValue();
                        vehicle += ((Long)recordMap.get(RecordType.vehicle)).longValue();
                        nonmotor += ((Long)recordMap.get(RecordType.nonmotor)).longValue();
                     }
                  }
               }
            retVal.put(name, new StructureCountVO(Long.valueOf(face), Long.valueOf(human), Long.valueOf(vehicle), Long.valueOf(nonmotor)));
         }
      }
      return retVal;
   }

   public StructureCountExVO cameraStructure(String cameraId) {
      Map<RecordType, Long> deviceMap = this.statisticsClient.typeDeviceTodayCount(cameraId);
      StructureCountExVO structureCountExVO = new StructureCountExVO();
      if (deviceMap.containsKey(RecordType.face))
         structureCountExVO.setFace(deviceMap.get(RecordType.face));
      if (deviceMap.containsKey(RecordType.body))
         structureCountExVO.setHuman(deviceMap.get(RecordType.body));
      if (deviceMap.containsKey(RecordType.vehicle))
         structureCountExVO.setVehicle(deviceMap.get(RecordType.vehicle));
      if (deviceMap.containsKey(RecordType.nonmotor))
         structureCountExVO.setNonmotor(deviceMap.get(RecordType.nonmotor));
      if (deviceMap.containsKey(RecordType.vehicle_alarm) && deviceMap.containsKey(RecordType.face_alarm))
         structureCountExVO.setAlarm(Long.valueOf(((Long)deviceMap.get(RecordType.vehicle_alarm)).longValue() + ((Long)deviceMap.get(RecordType.face_alarm)).longValue()));
      if (!deviceMap.containsKey(RecordType.vehicle_alarm) && deviceMap.containsKey(RecordType.face_alarm))
         structureCountExVO.setAlarm(deviceMap.get(RecordType.face_alarm));
      if (deviceMap.containsKey(RecordType.vehicle_alarm) && !deviceMap.containsKey(RecordType.face_alarm))
         structureCountExVO.setAlarm(deviceMap.get(RecordType.vehicle_alarm));
      return structureCountExVO;
   }

   public Map<String, Map<String, Integer>> statisticStructureNumber(FtrCondition conditions) {
      SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
      Map<String, Map<String, Integer>> structureMumberResult = new HashMap<>();
      if (conditions.getEndTime().longValue() - conditions.getStartTime().longValue() % 86400000L > 0L) {
         long index = (conditions.getEndTime().longValue() - conditions.getStartTime().longValue()) / 86400000L + 1L;
         long i;
         for (i = conditions.getStartTime().longValue(); i < conditions.getStartTime().longValue() + index * 86400000L; i += 86400000L) {
            FtrCondition condition = new FtrCondition();
            condition.setStartTime(Long.valueOf(i));
            condition.setEndTime(Long.valueOf(i + 86400000L));
            condition.setType(conditions.getType());
            Map<String, Integer> structureMumber = HandleType(condition);
            structureMumberResult.put(sf.format(new Date(i)), structureMumber);
         }
      }
      return structureMumberResult;
   }

   private Map<String, Integer> HandleType(FtrCondition condition) {
      int total = 0;
      Map<String, Integer> structureMumber = new HashMap<>();
      if (StringUtils.isNotBlank(condition.getType())) {
         String[] types = condition.getType().split(",");
         for (String type : types) {
            switch (Integer.parseInt(type)) {
               case 1:
                  total = this.faceResourceSearch.count((DefaultCondition)condition).intValue();
                  break;
               case 2:
                  total = this.bodyResourceSearch.count((DefaultCondition)condition).intValue();
                  break;
               case 4:
                  total = this.vehicleResourceSearch.count((DefaultCondition)condition).intValue();
                  break;
               case 8:
                  total = this.nonmotorResourceSearch.count((DefaultCondition)condition).intValue();
                  break;
            }
            if (Integer.parseInt(type) == SearchDataType.FACE.getIntValue())
               structureMumber.put("face", Integer.valueOf(total));
            if (Integer.parseInt(type) == SearchDataType.BODY.getIntValue())
               structureMumber.put("body", Integer.valueOf(total));
            if (Integer.parseInt(type) == SearchDataType.VEHICLE.getIntValue())
               structureMumber.put("vehicle", Integer.valueOf(total));
            if (Integer.parseInt(type) == SearchDataType.NONMOTOR.getIntValue())
               structureMumber.put("nonmotor", Integer.valueOf(total));
         }
      } else {
         int faceCount = this.faceResourceSearch.count((DefaultCondition)condition).intValue();
         int bodyCount = this.bodyResourceSearch.count((DefaultCondition)condition).intValue();
         int vehicleCount = this.vehicleResourceSearch.count((DefaultCondition)condition).intValue();
         int nonmotorCount = this.nonmotorResourceSearch.count((DefaultCondition)condition).intValue();
         total = faceCount + bodyCount + vehicleCount + nonmotorCount;
         structureMumber.put("Number", Integer.valueOf(total));
      }
      return structureMumber;
   }

   public Object venderInfo(Long startTime, Long endTime, String type) {
      SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
      Map<String, Map<String, Map<String, Long>>> structureMumberResult = new LinkedHashMap<>();
      if (endTime.longValue() - startTime.longValue() % 86400000L > 0L) {
         long index = (endTime.longValue() - startTime.longValue()) / 86400000L + 1L;
         long i;
         for (i = startTime.longValue(); i < startTime.longValue() + index * 86400000L; i += 86400000L) {
            Map<String, Map<String, Long>> structureMumber = HandleType(i, type);
            structureMumberResult.put(sf.format(new Date(i)), structureMumber);
         }
      }
      return structureMumberResult;
   }

   private Map<String, Map<String, Long>> HandleType(long time, String typeStr) {
      Map<String, Map<String, Long>> structureMumber = new HashMap<>();
      Map<String, Long> venderCountMap = new HashMap<>();
      String timePrefix = geneDayPrefix(time);
      if (StringUtils.isNotBlank(typeStr)) {
         String[] types = typeStr.split(",");
         for (String type : types) {
            Map<String, Long> venderCountMapTemp1, venderCountMapTemp2, venderCountMapTemp3;
            venderCountMap = new HashMap<>();
            switch (Integer.parseInt(type)) {
               case 1:
                  venderCountMapTemp1 = this.statisticsClient.venderCount(RecordType.face, timePrefix);
                  for (String key : venderCountMapTemp1.keySet()) {
                     if ("SenseTime".equals(key)) {
                        venderCountMap.put("st", venderCountMapTemp1.get(key));
                        continue;
                     }
                     if ("hikvision".equals(key)) {
                        venderCountMap.put("hk", venderCountMapTemp1.get(key));
                        continue;
                     }
                     if ("yitu1001".equals(key))
                        venderCountMap.put("yt", venderCountMapTemp1.get(key));
                  }
                  ckeckVenderCountMap(type, venderCountMap);
                  structureMumber.put("face", venderCountMap);
                  break;
               case 2:
                  venderCountMapTemp2 = this.statisticsClient.venderCount(RecordType.body, timePrefix);
                  for (String key : venderCountMapTemp2.keySet()) {
                     if ("SenseTime".equals(key)) {
                        venderCountMap.put("st", venderCountMapTemp2.get(key));
                        continue;
                     }
                     if ("hikvision".equals(key))
                        venderCountMap.put("hk", venderCountMapTemp2.get(key));
                  }
                  ckeckVenderCountMap(type, venderCountMap);
                  structureMumber.put("body", venderCountMap);
                  break;
               case 4:
                  venderCountMapTemp3 = this.statisticsClient.venderCount(RecordType.vehicle, timePrefix);
                  for (String key : venderCountMapTemp3.keySet()) {
                     if ("hikvision".equals(key))
                        venderCountMap.put("hk", venderCountMapTemp3.get(key));
                  }
                  ckeckVenderCountMap(type, venderCountMap);
                  structureMumber.put("vehicle", venderCountMap);
                  break;
            }
         }
      }
      return structureMumber;
   }

   private void ckeckVenderCountMap(String type, Map<String, Long> venderCountMap) {
      switch (Integer.parseInt(type)) {
         case 1:
            if (null == venderCountMap.get("st"))
               venderCountMap.put("st", Long.valueOf(0L));
            if (null == venderCountMap.get("hk"))
               venderCountMap.put("hk", Long.valueOf(0L));
            if (null == venderCountMap.get("yt"))
               venderCountMap.put("yt", Long.valueOf(0L));
            break;
         case 2:
            if (null == venderCountMap.get("dh"))
               venderCountMap.put("dh", Long.valueOf(0L));
            if (null == venderCountMap.get("hk"))
               venderCountMap.put("hk", Long.valueOf(0L));
            break;
         case 4:
            if (null == venderCountMap.get("hk"))
               venderCountMap.put("hk", Long.valueOf(0L));
            break;
      }
   }

   public String geneDayPrefix(long absTime) {
      try {
         return (new JDateTime(absTime)).toString("YYYYMMDD").substring(2);
      } catch (Exception e) {
         return "000000";
      }
   }
}
